import { CreateParams, DataProvider, DeleteManyParams, DeleteParams, fetchUtils, GetListParams, GetManyParams, GetManyReferenceParams, GetOneParams, UpdateManyParams, UpdateParams } from 'react-admin';
import { stringify } from 'query-string';
import { API_URL } from './constants/endpoints';

const httpClient = (url:string, options = {} as any) => {
    if (!options.headers) {
        options.headers = new Headers({ Accept: 'application/json' });
    }
    const token = localStorage.getItem('token');
    if(token){
        options.headers.set('Authorization', `Bearer ${token}`);
    }
    return fetchUtils.fetchJson(url, options);
};

const dataProvider: DataProvider =  {
    getList: async (resource: string, params: GetListParams) => {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
            sort: JSON.stringify([field, order]),
            range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
            filter: JSON.stringify(params.filter),
        };
        const url = `${API_URL}/${resource}?${stringify(query)}`;

        const { headers, json } = await httpClient(url);
        const contentRangeStr = headers.get('Content-Range');
        const contentRangeStrArr = contentRangeStr ? contentRangeStr.split('/') : [];
        const totalStr = contentRangeStrArr.pop();
        return {
            data: json,
            total: parseInt(totalStr ? totalStr : "0", 10),
        };
    },

    getOne: (resource:string, params: GetOneParams) =>
        httpClient(`${API_URL}/${resource}/${params.id}`).then(({ json }) => ({
            data: json,
        })),

    getMany: async (resource:string, params: GetManyParams) => {
        const query = {
            filter: JSON.stringify({ id: params.ids }),
        };
        const url = `${API_URL}/${resource}?${stringify(query)}`;
        const { json } = await httpClient(url);
        return ({ data: json });
    },

    getManyReference: async (resource:string, params: GetManyReferenceParams) => {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
            sort: JSON.stringify([field, order]),
            range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
            filter: JSON.stringify({
                ...params.filter,
                [params.target]: params.id,
            }),
        };
        const url = `${API_URL}/${resource}?${stringify(query)}`;

        const { headers, json } = await httpClient(url);
        const contentRangeStr = headers.get('content-range');
        const contentRangeStrArr = contentRangeStr ? contentRangeStr.split('/') : [];
        const totalStr = contentRangeStrArr.pop();
        return {
            data: json,
            total: parseInt(totalStr ? totalStr : "0", 10),
        };
    },

    update: (resource:string, params: UpdateParams) =>
        httpClient(`${API_URL}/${resource}/${params.id}`, {
            method: 'PUT',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({ data: json })),

    updateMany: async (resource:string, params: UpdateManyParams) => {
        const query = {
            filter: JSON.stringify({ id: params.ids }),
        };
        const { json } = await httpClient(`${API_URL}/${resource}?${stringify(query)}`, {
            method: 'PUT',
            body: JSON.stringify(params.data),
        });
        return ({ data: json });
    },

    create: (resource:string, params: CreateParams) =>
        httpClient(`${API_URL}/${resource}`, {
            method: 'POST',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({
            data: { ...params.data, id: json.id },
        })),

    delete: (resource:string, params: DeleteParams) =>
        httpClient(`${API_URL}/${resource}/${params.id}`, {
            method: 'DELETE',
        }).then(({ json }) => ({ data: json })),

    deleteMany: async (resource:string, params: DeleteManyParams) => {
        const query = {
            filter: JSON.stringify({ id: params.ids }),
        };
        const { json } = await httpClient(`${API_URL}/${resource}?${stringify(query)}`, {
            method: 'DELETE',
        });
        return ({ data: json });
    }
};

export default dataProvider;